package cn.anc.httpcontrolutil;

import android.os.Handler;
import android.util.Log;

import org.json.JSONObject;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import cn.anc.aonicardv.bean.FileBean;
import cn.anc.aonicardv.util.LogUtil;
import cn.anc.httpcontrolutil.cache.CacheManager;


/**
 * Created by baobaoding on 2017/4/26.
 */

public class CarControl {
    //jni call
    private native static int SendCommand(String ip, int port, int msg_id, String param1, String param2, String param3, byte[] outData, int bufferSize, int[] outLength);

    private native static int StartHeart(String ip, int port,String sendMsg,String responseMsg);

    private native static int StopHeart();

    private native static int SetDataParam(String ip, int port);

    private native static int SendData(String msg, int len);

    private static ExecutorService convertIdr2JpgThreadPool = Executors.newFixedThreadPool(10);
    private static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

    public static AtomicBoolean IsConnected = new AtomicBoolean(false);
    private static AtomicInteger get_thumbnail_run = new AtomicInteger(0);
    private static Handler handler = new Handler();
    private static String TAG = CarControl.class.getSimpleName();
    private static String m_ip = null;
    private static int m_port = -1;
    private static WeakReference mGuiErrorHandlerWeakReference;
    private static WeakReference mGuiNotificaionWeakReference;
    private static WeakReference mOnHeartBeatCallBackWeakReference;

    public interface OnCarControlCallback {
        void OnCommandCallback(int code, CommandResponseInfo info);
    }

    public interface OnCardvThumbnailCallback {
        void OnThumbnailGetted(int index);
    }

    public interface OnHeartBeatCallBack {
        void OnHeartBeatConnectOK();

        void OnHeartBeatConnectFail();

        void OnHeartBeatDisconnect();
    }

    public interface OnCarErrorHandler {
        void OnError(int error_code);
    }

    public interface OnNotificationHandler {
        void OnNotication(NotificationInfo info);
    }

    public static class CommandResponseInfo {
        public int msg_id = -1;
        public int rval = -1;
        public String type = null;
        public String param = null;
        public String event_param = null;

        public String toString() {
            return String.format(Locale.US, "msg_id=%d,rval=%d,type=%s,param=%s,event_param=%s", msg_id, rval, type, param, event_param);
        }
    }

    public static class DeviceInfo {
        public static String chip = null;
        public static String model = null;
        public static String brand = null;
        public static String fw_version = null;
        public static String device_sn = null;
        public static String build_time = null;
        public static String rtsp_url = null;
        public static String rear_rtsp_url = null;
        public static String rear = null;
        public static int record_status = 0;
        public static String file_server_port = null;
        //        如果存在ota_path字段：则使用ota_path value
//        如果不存在， 则为 http://[ip_header].1/?custom=1&fileupload
        public static String ota_path = null;
        //        如果存在get_thumb_on_rec字段
//        如果为1， 则支持拍照，录制小视频结束后下载缩略图提示分享功能
//        如果为0， 则不支持
//        如果不存在这个字段，则代表支持，默认为1
        public static int get_thumb_on_rec = 1;
        //        如果存在online_play字段，
//        如果为1， 则支持在线回放，和直接显示图片
//        如果为0， 则不支持，需要先下载
//        如果不存在，则代表支持，默认为1
        public static int online_play = 1;
        //        如果存在support_gps字段，
//        如果为1， 则支持传送gps数据
//        如果为0， 则不支持
        public static int support_gps = 1;

        public static void reset() {
            chip = null;
            model = null;
            brand = null;
            fw_version = null;
            device_sn = null;
            build_time = null;
            rtsp_url = null;
            rear_rtsp_url = null;
            rear = null;
            file_server_port = null;
            ota_path = null;
            get_thumb_on_rec = 1;
            online_play = 1;
            support_gps = 1;
            record_status = 0;
        }

        @Override
        public String toString() {
            return "DeviceInfo{" +
                    "chip='" + chip + '\'' +
                    ", model=" + model +
                    ", brand=" + brand +
                    ", fw_version=" + fw_version +
                    ", device_sn=" + device_sn +
                    ", build_time=" + build_time +
                    ", rtsp_url=" + rtsp_url +
                    ", rear_rtsp_url=" + rear_rtsp_url +
                    ", rear=" + rear +
                    ", file_server_port=" + file_server_port +
                    ", ota_path=" + ota_path +
                    ", get_thumb_on_rec=" + get_thumb_on_rec +
                    ", online_play=" + online_play +
                    ", support_gps=" + support_gps +
                    ", record_status=" + record_status +
                    '}';
        }
    }

    public static class NotificationInfo {
        public String type;
        public String param;
        public String event_param;
    }

    public static int setDataParam(String ip, int port) {
        return SetDataParam(ip, port);
    }

    public static int sendGpsData(String location, String name) {
        if (DeviceInfo.model.startsWith("NT")) {
            return -1;
        }
        StringBuilder unicodeBuffer = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            String tmp = "0000" + Integer.toHexString(name.charAt(i));
            unicodeBuffer.append(tmp.substring(tmp.length() - 4));
        }
        String msg = "GPS:" + location + "|" + unicodeBuffer.toString();
        return SendData(msg, msg.length());
    }

    public static int setParam(String ip, int port) {
        m_ip = ip;
        m_port = port;
        return 0;
    }

    public static void setOnHeartBeatCallBack(OnHeartBeatCallBack callBack) {
        mOnHeartBeatCallBackWeakReference = new WeakReference(callBack);
    }

    public static int setGuiErrorHandler(OnCarErrorHandler errorHandler) {
        mGuiErrorHandlerWeakReference = new WeakReference(errorHandler);
        return 0;
    }

    public static int setGuiNotificationHandler(OnNotificationHandler notificationHandler) {
        mGuiNotificaionWeakReference = new WeakReference(notificationHandler);
        return 0;
    }

    private static int guiCommandHandler(final OnCarControlCallback m_callback,
                                         final int code, final CommandResponseInfo info) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (m_callback != null) {
                    Log.e("----------", "-------code-------:" + code);
                    Log.e("----------", "-------info-------:" + info.toString());
                    m_callback.OnCommandCallback(code, info);
                }
            }
        });
        return 0;
    }


    /**
     * 校验MD5值
     *
     * @return
     */

    public static int doVerifyMd5(String md5, OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_SEND_FIREWARE_MD5, md5, onCarControlCallback);
    }


    /**
     * 执行记录仪拍照操作
     *
     * @return
     */
    public static int doTakePhoto(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_TAKE_PHOTO, onCarControlCallback);
    }


    /**
     * 获取记录仪当前是否录影
     *
     * @return
     */
    public static int doGetVideoSettingInfo(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_VIDEO_SETTING_INFO, onCarControlCallback);
    }

    /**
     * 获取记录仪设备信息
     *
     * @return
     */
    public static int doGetDeviceInfo(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_DEVICE_INFO, onCarControlCallback);
    }

    /**
     * 获取SD卡容量
     *
     * @return
     */
    public static int doGetSdCardSpace(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_GET_CARD_SPACE, onCarControlCallback);
    }


    /**
     * 记录仪录制短视频
     *
     * @return
     */
    public static int doRecordShortVideo(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_RECORD_SMALL_VIDEO, onCarControlCallback);
    }

    /**
     * 格式化记录仪的TF卡
     *
     * @return
     */
    public static int doFormatTFCard(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_FORMAT, onCarControlCallback);
    }

    /**
     * 记录仪恢复出厂设置
     *
     * @return
     */
    public static int doDefaultSetting(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_DEFAULT_SETTING, onCarControlCallback);
    }


    /**
     * 获取记录仪WIFI密码
     *
     * @param
     * @return
     */
    public static int doGetWifiPassword(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_GET_WIFI_PASSWORD, onCarControlCallback);
    }

    /**
     * 获取当前短视频录取详情
     *
     * @param
     * @return
     */
    public static int doGetSmallRecordStatus(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.APPHTTP_CONTROL_ID_GET_SMALL_RECORD_STATUS, onCarControlCallback);
    }

    /**
     * 获取记录仪的所有设置参数
     *
     * @return
     */
    public static int doGetAllSettings(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_ALL_SETTINGS, onCarControlCallback);
    }


    /**
     * 获取记录仪某一菜单的设置值
     *
     * @param item_name
     * @return
     */
    public static int doGetSettingItemValue(String item_name, OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_SETTING_ITEM, item_name, onCarControlCallback);
    }

    /**
     * 设置记录仪某一菜单的设置值
     *
     * @param item_name
     * @param item_value
     * @return
     */
    public static int doSetSettingItemValue(String item_name, String item_value, OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_SET_SETTING_ITEM, item_name, item_value, onCarControlCallback);
    }

    /**
     * 获取记录仪的文件列表
     *
     * @return
     */
    public static int doGetFileList(String media_type, OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_FILE_LIST, media_type, onCarControlCallback);
    }

    /**
     * 删除记录仪文件
     *
     * @param type            删除文件的类型
     * @param file_path_array 支持删除多个文件，最多支持同时删除10个文件
     * @return
     */
    public static int doDeleteFile(String type, List<String> file_path_array, OnCarControlCallback onCarControlCallback) {
        StringBuilder file_path_builder = new StringBuilder();
        if (file_path_array == null || file_path_array.size() <= 0 || file_path_array.size() > 10) {
            Log.e(TAG, "doDeleteFile: param error");
            return -1;
        }
        for (int i = 0; i < file_path_array.size(); i++) {
            file_path_builder.append(file_path_array.get(i));
            if (i == file_path_array.size() - 1) {
                break;
            }
            file_path_builder.append(",");
        }
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_DELETE_FILE, type, file_path_builder.toString(), onCarControlCallback);
    }

    /**
     * 移动记录仪文件
     *
     * @param type            移动文件的类型
     * @param file_path_array 支持移动多个文件，最多支持同时删除10个文件
     * @return
     */
    public static int doMoveFile(String type, List<String> file_path_array, OnCarControlCallback onCarControlCallback) {
        StringBuilder file_path_builder = new StringBuilder();
        if (file_path_array == null || file_path_array.size() <= 0 || file_path_array.size() > 10) {
            Log.e(TAG, "doMoveFile: param error");
            return -1;
        }
        for (int i = 0; i < file_path_array.size(); i++) {
            file_path_builder.append(file_path_array.get(i));
            if (i == file_path_array.size() - 1) {
                break;
            }
            file_path_builder.append(",");
        }
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_MOVE_FILE, type, file_path_builder.toString(), onCarControlCallback);
    }

    /**
     * 停止录像
     *
     * @return
     */
    public static int doStopRtsp(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_STOP_RTSP, onCarControlCallback);
    }

    /**
     * 开始录像
     *
     * @return
     */
    public static int doStartRtsp(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_START_RTSP, onCarControlCallback);
    }

    /**
     * 实时流界面录像控制
     *
     * @return
     */
    public static int doOnOffRtsp(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_ID_ON_OFF_RTSP, onCarControlCallback);
    }


    /**
     * 退出访问相册，记录仪会退出文件访问模式，开始录像
     *
     * @return
     */
    public static int doStopAccessFiles(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_END_ACCESS_FILES, onCarControlCallback);
    }

    /**
     * 修改wifi ssid
     *
     * @param ssid                 要修改的wifi名称
     * @param onCarControlCallback
     * @return
     */
    public static int doModifyWifiSetting(String ssid, OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_SET_WIFI_SETTING, ssid, onCarControlCallback);
    }

    /**
     * 修改wifi ssid和密码
     *
     * @param ssid                 要修改的wifi ssid
     * @param passwd               要修改的wifi 密码
     * @param onCarControlCallback
     * @return
     */
    public static int doModifyWifiSetting(String ssid, String passwd, OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.CAR_CONTROL_COMMAND_SET_WIFI_SETTING, ssid, passwd, onCarControlCallback);
    }


    /**
     * 获取当前实时流清晰度
     *
     * @return
     */
    public static int doGetLiveResolution(OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.APPHTTP_CONTROL_ID_GET_LIVE_RESOLUTION, onCarControlCallback);
    }

    /**
     * 获取当前实时流清晰度
     *
     * @return
     */
    public static int doSetLiveResolution(String resolution,OnCarControlCallback onCarControlCallback) {
        return SendCommand(CarControlCommand.APPHTTP_CONTROL_ID_SET_LIVE_RESOLUTION,resolution, onCarControlCallback);
    }


    private static void guiThumbnailCallback(final OnCardvThumbnailCallback m_callback, final int index) {

        if (m_callback != null) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    m_callback.OnThumbnailGetted(index);
                }
            });
        }
    }

    public static class CarDvThumbnailMediaInfo {
        public String raw_path = null;
        public String cache_path = null;
        public long size = 0;
        public String file_time = null;
        public String resolution = null;
        public int fps = 0;
        public long duration = 0;
        public String thumb_type = null;

        public String toString() {
            if (duration > 0) {
                return String.format(Locale.US, "%s,%s,%d,%d,%d",
                        file_time,
                        resolution,
                        duration,
                        size,
                        fps
                );
            } else
                return String.format(Locale.US, "%s,%d,%s",
                        file_time,
                        size,
                        resolution
                );
        }
    }

    private static CarDvThumbnailMediaInfo thumbnailMediaInfoParse(String media_info) {
        String[] info_array = media_info.split("\\|");
        if (info_array.length < 4) {//photo
            return null;
        }
        try {
            CarDvThumbnailMediaInfo mediaInfo = new CarDvThumbnailMediaInfo();
            mediaInfo.thumb_type = info_array[0];
            mediaInfo.raw_path = info_array[1];
            mediaInfo.size = Long.valueOf(info_array[2]);
            mediaInfo.resolution = info_array[3];
            mediaInfo.cache_path = CacheManager.getCachePath(mediaInfo.raw_path);
            mediaInfo.file_time = info_array[4];
            if (info_array.length > 5) {
                mediaInfo.fps = Integer.valueOf(info_array[5]);
                mediaInfo.duration = Long.valueOf(info_array[6]);
            }
            return mediaInfo;
        } catch (Exception ex) {
            Log.e(TAG, "thumbnailMediaInfoParse: " + ex.getMessage());
            return null;
        }
    }

    private static void thumbnailInfoParseHandler(final OnCardvThumbnailCallback m_callback,
                                                  final int index, byte[] data, final int data_len) {

        try {
            final String media_info;
            CarDvThumbnailMediaInfo mediaInfo = null;
            for (int i = 0; i < 128; i++) {
                if (data[i] == ',') {
                    media_info = new String(data, 0, i, "UTF-8");
                    mediaInfo = thumbnailMediaInfoParse(media_info);
                    if (mediaInfo == null) {
                        break;
                    }
                    if (mediaInfo.raw_path.endsWith(".MP4")) {
                        final byte[] _data = new byte[data_len];
                        final int _idx = i + 1;
                        final CarDvThumbnailMediaInfo _mediaInfo = mediaInfo;
                        System.arraycopy(data, 0, _data, 0, data_len);
                        convertIdr2JpgThreadPool.execute(new Runnable() {
                            @Override
                            public void run() {
                                CacheManager.saveToCache(_data, _idx, data_len - _idx, _mediaInfo);
                                File file = new File(_mediaInfo.cache_path);
                                if (file.exists())
                                    guiThumbnailCallback(m_callback, index);
                            }
                        });
                        return;
                    }

                    CacheManager.saveToCache(data, i + 1, data_len - (i + 1), mediaInfo);
                    break;
                }
            }
            File file = new File(mediaInfo.cache_path);
            if (file.exists())
                guiThumbnailCallback(m_callback, index);
        } catch (Exception ex) {
        }
    }

    /**
     * 获取记录仪某一文件的缩略图
     *
     * @return
     */
    public static int doGetPhotoThumbnail(final List<? extends FileBean> photoList, final List<Integer> idx_array, final OnCardvThumbnailCallback m_callback) {
        get_thumbnail_run.set(0);
        if (!IsConnected.get()) {
            guiErrorHandler(CarControlCommand.CarControlErrorCode.ERROR_CODE_APP_NOT_CONNECTED);
            return -1;
        }
        if (photoList == null ||
                photoList.size() <= 0 ||
                idx_array == null ||
                idx_array.size() <= 0) {
            return -1;
        }
        singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                get_thumbnail_run.set(1);
                byte[] outData = new byte[32 * 1024];
                int[] outLen = new int[1];
                int msg_id = CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_THUMB;
                int cur_idx = -1;
                for (int i = 0; i < idx_array.size(); i++) {
                    cur_idx = idx_array.get(i);
                    if (cur_idx >= photoList.size()) {
                        continue;
                    }
                    if (!IsConnected.get() || get_thumbnail_run.get() == 0) {
                        break;
                    }
                    if (CacheManager.checkCacheExist(photoList.get(cur_idx).getPath())) {
                        continue;
                    }
                    if (!IsConnected.get() || get_thumbnail_run.get() == 0) {
                        break;
                    }

                    int ret = SendCommand(m_ip, m_port, msg_id, photoList.get(cur_idx).getPath(), null, null, outData, outData.length, outLen);
                    if (ret >= 0) {
                        thumbnailInfoParseHandler(m_callback, cur_idx, outData, outLen[0]);
                    }
                }
                get_thumbnail_run.set(0);
            }
        });
        return 0;
    }

    public static int doGetVideoThumbnail(final List<? extends FileBean> videoList, final List<Integer> idx_array, final OnCardvThumbnailCallback m_callback) {
        get_thumbnail_run.set(0);
        if (!IsConnected.get()) {
            guiErrorHandler(CarControlCommand.CarControlErrorCode.ERROR_CODE_APP_NOT_CONNECTED);
            return -1;
        }
        if (videoList == null ||
                videoList.size() <= 0 ||
                idx_array == null ||
                idx_array.size() <= 0) {
            return -1;
        }
        singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                get_thumbnail_run.set(1);
                byte[] outData = new byte[1024 * 1024];
                int[] outLen = new int[1];
                int msg_id = CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_THUMB;
                int cur_idx = -1;
                for (int i = 0; i < idx_array.size(); i++) {
                    cur_idx = idx_array.get(i);
                    if (cur_idx >= videoList.size()) {
                        continue;
                    }
                    if (!IsConnected.get() || get_thumbnail_run.get() == 0) {
                        break;
                    }
                    if (CacheManager.checkCacheExist(videoList.get(cur_idx).getPath())) {
                        continue;
                    }
                    if (!IsConnected.get() || get_thumbnail_run.get() == 0) {
                        break;
                    }
                    int ret = SendCommand(m_ip, m_port, msg_id, videoList.get(cur_idx).getPath(), null, null, outData, outData.length, outLen);
                    if (ret >= 0) {
                        thumbnailInfoParseHandler(m_callback, cur_idx, outData, outLen[0]);
                    }
                }
                get_thumbnail_run.set(0);
            }
        });
        return 0;
    }

    public static void doStopGetThumbnail() {
        get_thumbnail_run.set(0);
    }

    private static int SendCommand(int msg_id, OnCarControlCallback onCarControlCallback) {
        return SendCommand(msg_id, null, null, null, onCarControlCallback);
    }

    private static int SendCommand(int msg_id, String param, OnCarControlCallback onCarControlCallback) {
        return SendCommand(msg_id, param, null, null, onCarControlCallback);
    }

    private static int SendCommand(int msg_id, String param1, String param2, OnCarControlCallback onCarControlCallback) {
        return SendCommand(msg_id, param1, param2, null, onCarControlCallback);
    }

    private static void guiErrorHandler(final int error_code) {
        if (mGuiErrorHandlerWeakReference != null && mGuiErrorHandlerWeakReference.get() != null) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    ((OnCarErrorHandler) mGuiErrorHandlerWeakReference.get()).OnError(error_code);
                }
            });
        }
    }

    private static int SendCommand(final int msg_id, final String param1, final String param2, final String param3, final OnCarControlCallback m_callback) {
        if (msg_id != CarControlCommand.CAR_CONTROL_COMMAND_GET_WIFI_PASSWORD && IsConnected.get() == false) {
            guiErrorHandler(CarControlCommand.CarControlErrorCode.ERROR_CODE_APP_NOT_CONNECTED);
            return -1;
        }
        singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
                byte[] outData;
                if (msg_id == CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_FILE_LIST) {
                    outData = new byte[1024 * 1024];
                } else {
                    outData = new byte[2 * 1024];
                }
                int[] outLen = new int[1];
                int ret = SendCommand(m_ip, m_port, msg_id, param1, param2, param3, outData, outData.length, outLen);
                MsgHandler(msg_id, ret, outData, outLen[0], m_callback);
            }
        });
        return 0;
    }

    private static int MsgHandler(int msg_id, final int code, byte[] data, int len, final OnCarControlCallback m_callback) {
        try {
            CommandResponseInfo info = new CommandResponseInfo();
            if (msg_id == CarControlCommand.CAR_CONTROL_COMMAND_ID_GET_DEVICE_INFO) {
                String readBuffer = new String(data, 0, len, "UTF-8");
                JSONObject obj = new JSONObject(readBuffer);
                LogUtil.e("llcDebug", "----obj---:" + obj.toString());
                if (obj.has("msg_id")) {
                    info.msg_id = obj.getInt("msg_id");
                }
                if (obj.has("brand")) {
                    DeviceInfo.brand = obj.getString("brand");
                }
                if (obj.has("model")) {
                    DeviceInfo.model = obj.getString("model");
                }
                if (obj.has("chip")) {
                    DeviceInfo.chip = obj.getString("chip");
                }
                if (obj.has("fw_ver")) {
                    DeviceInfo.fw_version = obj.getString("fw_ver");
                }
                if (obj.has("sn")) {
                    DeviceInfo.device_sn = obj.getString("sn");
                }
                if (obj.has("build_time")) {
                    DeviceInfo.build_time = obj.getString("build_time");
                }
                if (obj.has("rtsp_url")) {
                    DeviceInfo.rtsp_url = obj.getString("rtsp_url");
                }
                if (obj.has("rear_rtsp_url")) {
                    DeviceInfo.rear_rtsp_url = obj.getString("rear_rtsp_url");
                }
                if (obj.has("rear")) {
                    DeviceInfo.rear = obj.getString("rear");
                }
                if (obj.has("record_status")) {
                    DeviceInfo.record_status = obj.getInt("record_status");
                }
                if (obj.has("file_server_port")) {
                    DeviceInfo.file_server_port = obj.getString("file_server_port");
                }
                if (obj.has("online_play")) {
                    DeviceInfo.online_play = obj.getInt("online_play");
                }
                if (obj.has("support_gps")) {
                    DeviceInfo.support_gps = obj.getInt("support_gps");
                }
                if (obj.has("get_thumb_on_rec")) {
                    DeviceInfo.get_thumb_on_rec = obj.getInt("get_thumb_on_rec");
                }
                if (obj.has("ota_path")) {
                    DeviceInfo.ota_path = obj.getString("ota_path");
                }

                if (m_callback != null) {
                    guiCommandHandler(m_callback, code, info);
                }
                return 0;
            }
            if (m_callback != null) {
                String readBuffer = new String(data, 0, len, "UTF-8");
                JSONObject obj = new JSONObject(readBuffer);
                if (code < 0) {
                    info.msg_id = msg_id;
                    guiCommandHandler(m_callback, code, info);
                    return 0;
                }
                Log.e(TAG, "------obj: " + obj.toString());
                if (obj.has("msg_id")) {
                    info.msg_id = obj.getInt("msg_id");
                }
                if (obj.has("rval")) {
                    info.rval = obj.getInt("rval");
                }
                if (obj.has("param")) {
                    info.param = obj.getString("param");
                }
                if (obj.has("type")) {
                    info.type = obj.getString("type");
                }
                if (obj.has("event_param")) {
                    info.event_param = obj.getString("event_param");
                }
                if (info.rval < 0) {
                    guiErrorHandler(info.rval);
                }
                guiCommandHandler(m_callback, code, info);
                Runtime.getRuntime().gc();
            }
        } catch (Exception ex) {
            CommandResponseInfo erroInfo = new CommandResponseInfo();
            guiCommandHandler(m_callback, code, erroInfo);
            Runtime.getRuntime().gc();
            return -1;
        }
        return 0;
    }

    /**
     * call heart beat, native will create thread
     *
     * @param ip
     * @param port
     * @return
     */
    public static int HeartBeatStart(String ip, int port,String sendMsg,String responseMsg) {
        if (IsConnected.get()) {
            return -1;
        }
        return StartHeart(ip, port,sendMsg,responseMsg);
    }

    /**
     * 结束heart beat thread
     *
     * @return
     */
    public static int HeartBeatStop() {
        return StopHeart();
    }

    /**
     * native code call this for car notification message
     *
     * @param msg message
     */
    private static void CallJavaNotification(final String msg) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    NotificationInfo info = new NotificationInfo();
                    JSONObject obj = new JSONObject(msg);
                    if (obj.has("type")) {
                        info.type = obj.getString("type");
                    }
                    if (obj.has("param")) {
                        info.param = obj.getString("param");
                    }
                    if (mGuiNotificaionWeakReference.get() != null) {
                        ((OnNotificationHandler) mGuiNotificaionWeakReference.get()).OnNotication(info);
                    }
                    if (info.type.equals("disconnect")) {
                        HeartBeatStop();
                    }
                } catch (Exception ex) {
                    Log.w(TAG, "CallJavaNotification: " + ex.getMessage());
                }
            }
        });
    }

    /**
     * connect to heart beat server ok
     */
    private static void CallJavaHeartBeatConnectOk() {
        IsConnected.set(true);
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (mOnHeartBeatCallBackWeakReference.get() != null) {
                    ((OnHeartBeatCallBack) mOnHeartBeatCallBackWeakReference.get()).OnHeartBeatConnectOK();
                }
            }
        });
    }

    private static void CallJavaHeartBeatConnectFail() {
        IsConnected.set(false);
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (mOnHeartBeatCallBackWeakReference.get() != null) {
                    ((OnHeartBeatCallBack) mOnHeartBeatCallBackWeakReference.get()).OnHeartBeatConnectFail();
                }
            }
        });
    }

    /**
     * heart beat disconnect
     */
    private static void CallJavaHeartBeatDisconnect() {
        IsConnected.set(false);
        DeviceInfo.reset();
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (mOnHeartBeatCallBackWeakReference.get() != null) {
                    ((OnHeartBeatCallBack) mOnHeartBeatCallBackWeakReference.get()).OnHeartBeatDisconnect();
                }
            }
        });
    }

    /**
     * connect to heart beat server ok
     */
    private static void CallBindSocketToWifiNetwork(int socket_fd) {
        SocketUtils.bindSocketToWifiNetwork(socket_fd);
    }


    static {
        System.loadLibrary("CarControl");
    }
}
